{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Java StringBuffer 和 StringBuilder 类\n",
    "当`对字符串进行修改`的时候，需要使用 StringBuffer 和 StringBuilder 类。\n",
    "\n",
    "和 String 类不同的是，StringBuffer 和 StringBuilder 类的对象能够被多次的修改，并且不产生新的未使用对象。\n",
    "\n",
    "StringBuilder 类在 Java 5 中被提出，它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的（不能同步访问）。\n",
    "\n",
    "由于 StringBuilder 相较于 StringBuffer 有速度优势，所以多数情况下建议使用 StringBuilder 类。然而在应用程序要求线程安全的情况下，则必须使用 StringBuffer 类。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## StringBuffer 方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "以下是 StringBuffer 类支持的主要方法：\n",
    "\n",
    "|序号|  方法|描述|\n",
    "|:---|:-----|:------|\n",
    "|1|\tpublic StringBuffer append(String s)| 将指定的字符串追加到此字符序列。|\n",
    "|2|\tpublic StringBuffer reverse()| 将此字符序列用其反转形式取代。|\n",
    "|3|\tpublic delete(int start, int end)| 移除此序列的子字符串中的字符。|\n",
    "|4|\tpublic insert(int offset, int i)| 将 int 参数的字符串表示形式插入此序列中。|\n",
    "|5|\treplace(int start, int end, String str)| 使用给定 String 中的字符替换此序列的子字符串中的字符。|"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-10-30T12:17+0000",
     "start_time": "2020-10-30T12:17:18.793Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "菜鸟教程官网：www.runoob.com\n"
     ]
    }
   ],
   "source": [
    "StringBuffer sBuffer = new StringBuffer(\"菜鸟教程官网：\");\n",
    "sBuffer.append(\"www\");\n",
    "sBuffer.append(\".runoob\");\n",
    "sBuffer.append(\".com\");\n",
    "System.out.println(sBuffer);  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-10-30T12:20+0000",
     "start_time": "2020-10-30T12:20:25.542Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "anlzouwww.anlzoucomѾ\n"
     ]
    }
   ],
   "source": [
    "StringBuilder sBuilder = new StringBuilder(\"anlzou\");\n",
    "sBuilder.append(\"www\");\n",
    "sBuilder.append(\".anlzou\");\n",
    "sBuilder.append(\"com\");\n",
    "sBuilder.append(\"Ѿ\");\n",
    "System.out.println(sBuilder)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "下面的列表里的方法和 String 类的方法类似：\n",
    "\n",
    "|序号|方法|描述|\n",
    "|:---|:---|:---|\n",
    "|1|\tint capacity()|返回当前容量。|\n",
    "|2|\tchar charAt(int index)|返回此序列中指定索引处的 char 值。|\n",
    "|3|\tvoid ensureCapacity(int minimumCapacity)|确保容量至少等于指定的最小值。|\n",
    "|4|\tvoid getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)|将字符从此序列复制到目标字符数组 dst。|\n",
    "|5|\tint indexOf(String str)|返回第一次出现的指定子字符串在该字符串中的索引。|\n",
    "|6|\tint indexOf(String str, int fromIndex)|从指定的索引处开始，返回第一次出现的指定子字符串在该字符串中的索引。|\n",
    "|7|\tint lastIndexOf(String str)|返回最右边出现的指定子字符串在此字符串中的索引。|\n",
    "|8|\tint lastIndexOf(String str, int fromIndex)|返回 String 对象中子字符串最后出现的位置。|\n",
    "|9|\tint length()|返回长度（字符数）。|\n",
    "|10|\tvoid setCharAt(int index, char ch)|将给定索引处的字符设置为 ch。|\n",
    "|11|\tvoid setLength(int newLength)|设置字符序列的长度。|\n",
    "|12|\tCharSequence subSequence(int start, int end)|返回一个新的字符序列，该字符序列是此序列的子序列。|\n",
    "|13|\tString substring(int start)|返回一个新的 String，它包含此字符序列当前所包含的字符子序列。|\n",
    "|14|\tString substring(int start, int end)|返回一个新的 String，它包含此序列当前所包含的字符子序列。|\n",
    "|15|\tString toString()|返回此序列中数据的字符串表示形式。|"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 补充：Java 中的 StringBuilder 和 StringBuffer 适用的场景是什么？\n",
    "最简单的回答是，stringbuffer 基本没有适用场景，你应该在所有的情况下选择使用 stringbuiler，除非你真的遇到了一个需要线程安全的场景，如果遇到了，请务必在这里留言通知我。\n",
    "\n",
    "然后，补充一点，关于线程安全，即使你真的遇到了这样的场景，很不幸的是，恐怕你仍然有 99.99....99% 的情况下没有必要选择 stringbuffer，因为 stringbuffer 的线程安全，仅仅是保证 jvm 不抛出异常顺利的往下执行而已，它可不保证逻辑正确和调用顺序正确。大多数时候，我们需要的不仅仅是线程安全，而是锁。\n",
    "\n",
    "最后，为什么会有 stringbuffer 的存在，如果真的没有价值，为什么 jdk 会提供这个类？答案太简单了，因为最早是没有 stringbuilder 的，sun 的人不知处于何种愚蠢的考虑，决定让 stringbuffer 是线程安全的，然后大约 10 年之后，人们终于意识到这是一个多么愚蠢的决定，意识到在这 10 年之中这个愚蠢的决定为 java 运行速度慢这样的流言贡献了多大的力量，于是，在 jdk1.5 的时候，终于决定提供一个非线程安全的 stringbuffer 实现，并命名为 stringbuilder。顺便，javac 好像大概也是从这个版本开始，把所有用加号连接的 string 运算都隐式的改写成 stringbuilder，也就是说，从 jdk1.5 开始，用加号拼接字符串已经没有任何性能损失了。\n",
    "\n",
    "如诸多评论所指出的，我上面说，\"用加号拼接字符串已经没有任何性能损失了\"并不严谨，严格的说，如果没有循环的情况下，单行用加号拼接字符串是没有性能损失的，java 编译器会隐式的替换成 stringbuilder，但在有循环的情况下，编译器没法做到足够智能的替换，仍然会有不必要的性能损耗，因此，用循环拼接字符串的时候，还是老老实实的用 stringbuilder 吧。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 补充：StringBuffer 和 String 是有的区别\n",
    "ava 中 StringBuffer 和 String 是有一定的区别的，首先，String 是被 final 修饰的，他的长度是不可变的，就算调用 String 的 concat 方法，那也是把字符串拼接起来并重新创建一个对象，把拼接后的 String 的值赋给新创建的对象，而 StringBuffer 的长度是可变的，调用StringBuffer 的 append 方法，来改变 StringBuffer 的长度，并且，相比较于 StringBuffer，String 一旦发生长度变化，是非常耗费内存的！"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Java",
   "language": "java",
   "name": "java"
  },
  "language_info": {
   "codemirror_mode": "java",
   "file_extension": ".jshell",
   "mimetype": "text/x-java-source",
   "name": "Java",
   "pygments_lexer": "java",
   "version": "11.0.8+10-post-Ubuntu-0ubuntu120.04"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {
    "height": "calc(100% - 180px)",
    "left": "10px",
    "top": "150px",
    "width": "165px"
   },
   "toc_section_display": true,
   "toc_window_display": false
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
